using SqlSugar;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Yuebon.Commons.Cache;
using Yuebon.Commons.Helpers;
using Yuebon.Commons.Options;

namespace Yuebon.Security.Services
{
    /// <summary>
    /// 发票信息服务接口实现
    /// </summary>
    public partial class THInvoiceService: BaseService<THInvoice,THInvoiceOutputDto>, ITHInvoiceService
    {
        private readonly IUserRepository _userRepository;
        private readonly IOrganizeRepository _organizeRepository;
        public THInvoiceService(ITHInvoiceRepository _repository, IUserRepository userRepository, IOrganizeRepository organizeRepository)
        {
			repository=_repository;
            _userRepository = userRepository;
            _organizeRepository = organizeRepository;
        }

        /// <summary>
        /// 根据条件查询数据库,并返回对象集合(用于分页数据显示)
        /// </summary>
        /// <param name="search">查询的条件</param>
        /// <returns>指定对象的集合</returns>
        public async Task<PageResult<THInvoiceOutputDto>> SearchPageList(InvoiceQueryModel search)
        {
            bool order = search.Order == "asc" ? false : true;

            var identities = HttpContextHelper.HttpContext.User.Identities;
            var claimsIdentity = identities.First<ClaimsIdentity>();
            List<Claim> claimlist = claimsIdentity.Claims as List<Claim>;

            var userId = long.Parse(claimlist[0].Value);
            string taxCode = "";

            if (claimlist.Count > 0){
                var user = _userRepository.GetById(userId);
                if (user != null && user.CreateOrgId != null)
                {
                    var o = _organizeRepository.GetById(user.CreateOrgId.Value);
                    taxCode = o == null ? "" : o.TaxIdenCode;
                }
            }            

            var expressionWhere = Expressionable.Create<THInvoice>()
               .AndIF(!string.IsNullOrEmpty(search.Keywords), it => it.InvoiceNo.Contains(search.Keywords))
               .AndIF(!string.IsNullOrEmpty(search.Status), it => it.CheckStatus.Contains(search.Status))
               .AndIF(!string.IsNullOrEmpty(taxCode), it => it.BuyerCode==taxCode)
               .AndIF(!string.IsNullOrEmpty(search.Filter.InvoiceKind) && search.Filter.InvoiceKind == "1", it => it.Money>0)
               .AndIF(!string.IsNullOrEmpty(search.Filter.InvoiceKind) && search.Filter.InvoiceKind == "-1", it => it.Money < 0)
               .AndIF(search.DateRange.Length>0, it => Convert.ToDateTime(it.InvoiceDate)>= Convert.ToDateTime(search.DateRange[0]) && Convert.ToDateTime(it.InvoiceDate) <= Convert.ToDateTime(search.DateRange[1]))
               .AndIF(search.Filter.CheckTimeRange!=null && search.Filter.CheckTimeRange.Length>0, it => it.CheckTime>= Convert.ToDateTime(search.Filter.CheckTimeRange[0]) && it.CheckTime<= Convert.ToDateTime(search.Filter.CheckTimeRange[1]))
               .AndIF(!string.IsNullOrEmpty(search.Filter?.SalerName), it => it.SalerName.Contains(search.Filter.SalerName) || it.SalerCode.Contains(search.Filter.SalerName))
               .ToExpression();

            var allInvoices = await repository.GetAll(expressionWhere);

           
            PagerInfo pagerInfo = new PagerInfo
            {
                CurrenetPageIndex = search.CurrenetPageIndex,
                PageSize = search.PageSize
            };
            List<THInvoice> list = await repository.FindWithPagerAsync(expressionWhere, pagerInfo, search.Sort, order);
            PageResult<THInvoiceOutputDto> pageResult = new PageResult<THInvoiceOutputDto>
            {
                CurrentPage = pagerInfo.CurrenetPageIndex,
                Items = list.MapTo<THInvoiceOutputDto>(),
                ItemsPerPage = pagerInfo.PageSize,
                TotalItems = pagerInfo.RecordCount,
                Context = allInvoices.Sum(x=>x.Money)
            };
            return pageResult;
        }

        /// <summary>
        /// 通过发票号查询发票
        /// </summary>
        /// <param name="invoiceNo"></param>
        /// <returns></returns>

        public async Task<List<THInvoice>> SearchInvoiceList(string invoiceNo)
        {
            var identities = HttpContextHelper.HttpContext.User.Identities;
            var claimsIdentity = identities.First<ClaimsIdentity>();
            List<Claim> claimlist = claimsIdentity.Claims as List<Claim>;

            var userId = long.Parse(claimlist[0].Value);
            string taxCode = "";

            if (claimlist.Count > 0)
            {
                var user = _userRepository.GetById(userId);
                if (user != null && user.CreateOrgId != null)
                {
                    var o = _organizeRepository.GetById(user.CreateOrgId.Value);
                    taxCode = o == null ? "" : o.TaxIdenCode;
                }
            }

            var expressionWhere = Expressionable.Create<THInvoice>()
               .AndIF(!string.IsNullOrEmpty(taxCode),it=> it.BuyerCode == taxCode)
               .AndIF(!string.IsNullOrEmpty(invoiceNo), it => it.InvoiceNo.Contains(invoiceNo))               
               .ToExpression();

            var allInvoices = await repository.GetAll(expressionWhere);

            return allInvoices;
                
        }

        /// <summary>
        /// 扫描发票
        /// </summary>
        /// <param name="invoice"></param>
        /// <returns></returns>
        public async Task<InvoiceScanOutDto> ScanInvoiceNo(string invoice)
        {
            var result = new InvoiceScanOutDto();
            if (string.IsNullOrEmpty(invoice))
            {
                result.invoiceResult = "请输入发票信息！";
                result.invoiceColor = "red";
                return result;
            }
            invoice = invoice.Trim().Replace("，", ",");// 中文','处理 
            string[] invoiceTemp = invoice.Split(',');
            
            if (invoiceTemp.Length >= 8)
            {
                // 编码判定
               result = _getInvoiceDetail(invoiceTemp);
            }
            else
            {
                result.invoiceResult = "发票格式错误！";
                result.invoiceColor = "red";
            }
            return result;
        }

        /// <summary>
        /// 导入核验发票
        /// </summary>
        /// <param name="invoice"></param>
        /// <returns></returns>
        public async Task<List<InvoiceScanOutDto>> ImportInvoices(string filePath)
        {
            List<InvoiceScanOutDto> result;
            try
            {                
                DataTable dt = NPOIHelper.ImportExcel(filePath);
                if (!DataTableHelper.IsHaveRows(dt))
                {
                    return null;                    
                }

                result = DataTableHelper.DataTableToList<InvoiceScanOutDto>(dt);
                result.ForEach(x =>
                {
                    x.invoiceResult = "未核";
                });
                return result;

            }
            catch(Exception ex)
            {
                return null;
            }
            
        }

        /// <summary>
        /// 去掉已核发票
        /// </summary>
        /// <param name="invoices"></param>
        /// <returns></returns>
        public async Task<List<InvoiceScanOutDto>> FilterInvoice(List<InvoiceScanOutDto> invoices)
        {
            List<InvoiceScanOutDto> result = new List<InvoiceScanOutDto>();
            invoices.ForEach(x =>
            {
                THInvoice invoice = repository.GetWhere(string.Format(" InvoiceNo = '{0}'", x.InvoiceNo));
                if ( invoice != null && invoice.CheckStatus=="未核")
                {
                    result.Add(x);
                }
            });
            return result;
        }

        /// <summary>
        /// 批量核验发票
        /// </summary>
        /// <param name="invoices"></param>
        /// <returns></returns>
        public async Task<List<InvoiceScanOutDto>> BatchInvoice(List<InvoiceScanOutDto> invoices)
        {
            List<InvoiceScanOutDto> result = new List<InvoiceScanOutDto>();
            var waitInvoices = new List<THInvoice>();
            invoices.ForEach(x =>
            {
                THInvoice invoice = repository.GetWhere(string.Format(" InvoiceNo = '{0}'", x.InvoiceNo));
                if (invoice != null && invoice.CheckStatus == "未核")
                {
                    if (x.InvoiceDate == invoice.InvoiceDate && x.Money == invoice.Money)
                    {
                        invoice.CheckStatus = "已核";
                        invoice.CheckTime = DateTime.Now;
                        waitInvoices.Add(invoice);
                        x.invoiceResult = "已核";                       
                    }
                    else
                    {
                        x.invoiceResult = "核验失败";
                    }
                    result.Add(x);
                }
            });

            if (waitInvoices.Count > 0)
            {
                int insertNum = 0;
                int updateNum = 0;
                repository.InsertOrUpdate(waitInvoices,out insertNum,out updateNum);
            }
            return result;
        }

        public async Task<string> ExportInvoice(InvoiceQueryModel search, string path)
        {
            bool order = search.Order == "asc" ? false : true;

            var identities = HttpContextHelper.HttpContext.User.Identities;
            var claimsIdentity = identities.First<ClaimsIdentity>();
            List<Claim> claimlist = claimsIdentity.Claims as List<Claim>;

            var userId = long.Parse(claimlist[0].Value);
            string taxCode = "";

            if (claimlist.Count > 0)
            {
                var user = _userRepository.GetById(userId);
                if (user != null && user.CreateOrgId != null)
                {
                    var o = _organizeRepository.GetById(user.CreateOrgId.Value);
                    taxCode = o == null ? "" : o.TaxIdenCode;
                }
            }

            var expressionWhere = Expressionable.Create<THInvoice>()
               .AndIF(!string.IsNullOrEmpty(search.Keywords), it => it.InvoiceNo.Contains(search.Keywords))
               .AndIF(!string.IsNullOrEmpty(search.Status), it => it.CheckStatus.Contains(search.Status))
               .AndIF(!string.IsNullOrEmpty(taxCode), it => it.BuyerCode == taxCode)
               .AndIF(!string.IsNullOrEmpty(search.Filter.InvoiceKind) && search.Filter.InvoiceKind == "1", it => it.Money > 0)
               .AndIF(!string.IsNullOrEmpty(search.Filter.InvoiceKind) && search.Filter.InvoiceKind == "-1", it => it.Money < 0)
               .AndIF(search.DateRange.Length > 0, it => Convert.ToDateTime(it.InvoiceDate) >= Convert.ToDateTime(search.DateRange[0]) && Convert.ToDateTime(it.InvoiceDate) <= Convert.ToDateTime(search.DateRange[1]))
               .AndIF(search.Filter.CheckTimeRange != null && search.Filter.CheckTimeRange.Length > 0, it => it.CheckTime >= Convert.ToDateTime(search.Filter.CheckTimeRange[0]) && it.CheckTime <= Convert.ToDateTime(search.Filter.CheckTimeRange[1]))
               .AndIF(!string.IsNullOrEmpty(search.Filter?.SalerName), it => it.SalerName.Contains(search.Filter.SalerName) || it.SalerCode.Contains(search.Filter.SalerName))
               .ToExpression();


            PagerInfo pagerInfo = new PagerInfo
            {
                CurrenetPageIndex = search.CurrenetPageIndex,
                PageSize = 10000
            };

            try
            {
                List<THInvoice> list = await repository.FindWithPagerAsync(expressionWhere, pagerInfo, search.Sort, order);
                var showList = list.Select(x => new InvoiceExcelOutDto
                {
                    InvoiceKind = x.InvoiceKind,
                    InvoiceNo = x.InvoiceNo,
                    InvoiceDate = x.InvoiceDate,
                    Money = x.Money??0M,
                    CheckStatus = x.CheckStatus,
                    CheckTime = x.CheckTime.HasValue ? x.CheckTime.ToString() : "",
                    CheckName = x.CheckName,
                    SalerCode = x.SalerCode,
                    SalerName = x.SalerName                   

                }).ToList();
                DataTable dt = DataTableHelper.ToDataTable<InvoiceExcelOutDto>(showList);
                string _filePath = path + "\\export\\";
                if (!Directory.Exists(_filePath))
                {
                    Directory.CreateDirectory(_filePath);
                }
                string fileName = "invoice" + DateTime.Now.ToString("yyyyMMdd") + new Random().Next(10000) + ".xlsx"; 
                NPOIHelper.ExportExcel(dt, "发票信息", _filePath+fileName);
                return fileName;
            }
            catch (Exception ex)
            {
                return "error";
            }
            
        }

        private InvoiceScanOutDto _getInvoiceDetail(string[] strCode)
        {
            var result = new InvoiceScanOutDto();
            // 取发票号码信息            
            string invoiceCode = strCode[2];
            string invoiceNo = strCode[3];
            decimal money = 0M;
            decimal.TryParse(strCode[4], out money);
            string invoiceDate = strCode[5];
            try
            {
                //发票号码处理
                THInvoice invoice = repository.GetWhere(string.Format(" InvoiceNo = '{0}'", invoiceNo));
                if (invoice == null)
                {
                    result.invoiceResult = "未找到发票信息！";
                    result.invoiceColor = "red";
                    return result;

                }

                if (invoice.CheckStatus == "已核")
                {
                    result.invoiceResult = "该发票已核对！";
                    result.invoiceColor = "red";
                    return result;
                }
                var dzInvoiceDate = Convert.ToDateTime(invoice.InvoiceDate).ToString("yyyyMMdd");
                if (dzInvoiceDate != invoiceDate)
                {
                    result.invoiceResult = "发票时间错误！";
                    result.invoiceColor = "red";
                    return result;
                }

                if (Math.Abs(invoice.Money.Value) != Math.Abs(money) && Math.Abs(invoice.Money.Value)-Math.Abs(invoice.Tax.Value)!= Math.Abs(money))
                {
                    result.invoiceResult = "发票金额错误！";
                    result.invoiceColor = "red";
                    return result;
                }

                var identities = HttpContextHelper.HttpContext.User.Identities;
                var claimsIdentity = identities.First<ClaimsIdentity>();
                List<Claim> claimlist = claimsIdentity.Claims as List<Claim>;

                var account = claimlist[1].Value;
                invoice.CheckStatus = "已核";
                invoice.CheckTime = DateTime.Now;
                invoice.CheckName = account;
                repository.Update(invoice);
                result.InvoiceNo  = invoice.InvoiceNo;
                result.InvoiceDate = invoiceDate;
                result.Money = invoice.Money??0M;
                result.invoiceResult = "核对成功！";
                result.invoiceColor = "green";
                return result;
            }
            catch
            {
                result.invoiceResult = "服务器错误！";
                result.invoiceColor = "red";
                return result;
            }
        }
    }
}